package com.mikelouis.test.scala.impatient.chapter13_collections

import scala.collection.immutable.{SortedMap, SortedSet}
import scala.collection.mutable

/**
 * Created by yuazhu on 4/24/2015.
 */
object Chapter13 {
  // 1
  def indexes(str: Seq[Char]): mutable.LinkedHashMap[Char, mutable.LinkedHashSet[Int]] = {
    val map = new mutable.LinkedHashMap[Char, mutable.LinkedHashSet[Int]]
    var elem: mutable.LinkedHashSet[Int] = null
    for (charIndex <- str.zipWithIndex) {
      elem = map.getOrElseUpdate(charIndex._1, mutable.LinkedHashSet())
      elem += charIndex._2
    }
    map
  }

  // 2
  def charIndex(str: String, index: Int): SortedMap[Char, SortedSet[Int]] = {
    if (str.isEmpty) {
      SortedMap()
    }
    else {
      val nextMap = charIndex(str.tail, index + 1)
      nextMap + (str(0)
        -> (nextMap.getOrElse(str(0), SortedSet[Int]()) ++ SortedSet(index)))
    }
  }

  // 3
  def rmZeros[A](l: List[A])(fun: A => Boolean): List[A] = l.filter(fun)

  // 4
  def strListToIndexList(strList: Seq[String], strMap: Map[String, Int]) = strList.flatMap(strMap.get)

  // 5
  def mkStringUsingReduceLeft(l: Seq[String], start: String = "[", sep: String = ",", end: String = "]") = start + l.reduceLeft(_ + sep + _) + end

  // 6
  def fun1(lst: List[Int]) = (lst :\ List[Int]())(_ :: _) // lst.foldRight(List[Int]())(_::_) foldRight then concat to right, gets the same list as input lst

  def fun2(lst: List[Int]) = (List[Int]() /: lst)(_ :+ _) // lst.foldLeft(List[Int]())(_:+_)

  def reverse(lst: List[Int]) = (lst :\ List[Int]())((x, y) => y ++ List(x))

  def reverse2(lst: List[Int]) = (List[Int]() /: lst)((x, y) => y +: x)

  // 7
  def mapTuple(lstA: Seq[Double], lstB: Seq[Int], fun: (Double, Int) => Double) = (lstA zip lstB) map fun.tupled

  def calcPrices(prices: Seq[Double], quantities: Seq[Int]) =
    (prices zip quantities) map {
      // tupled method of Function will accept tuple input
      ((p: Double, q: Int) => p * q).tupled
    }

  // 8
  def splitSeq[A](lst: Seq[A], group: Int): Seq[Seq[A]] = lst.grouped(group).toList

  // 9 TODO

  // 10 TODO


  def main(args: Array[String]) {
    println(indexes("Mississippi"))

    println(charIndex("Mississippi", 0))

    println(rmZeros(List(1, 0, 7, 3, 0, 10))(x => x != 0))

    println(strListToIndexList(Array("Tom", "Fred", "Harry"), Map("Tom" -> 3, "Dick" -> 4, "Harry" -> 5)))

    println(mkStringUsingReduceLeft(Array("Tom", "Fred", "Harry")))

    println(fun1(List(1, 0, 7, 3, 0, 10)))
    println(fun2(List(1, 0, 7, 3, 0, 10)))
    println(reverse(List(1, 0, 7, 3, 0, 10)))
    println(reverse2(List(1, 0, 7, 3, 0, 10)))

    val prices = List(5.0, 20.0, 9.95)
    val quantities = List(10, 2, 1)
    println(mapTuple(prices, quantities, (a: Double, b: Int) => a * b))
    println(calcPrices(prices, quantities))

    println(splitSeq(List(1, 2, 3, 4, 5, 6), 3))
  }
}
